using AutoMapper;
using MediatR;
using Microsoft.EntityFrameworkCore;
using S.M.SmartMedical.API.Write.Application.Command;
using S.M.SmartMedical.Domain.Entities;
using S.M.SmartMedical.Domain.Enums;
using S.M.SmartMedical.ErrorCode;
using S.M.SmartMedical.Infrastructure;
using S.M.SmartMedical.Infrastructure.BaseRepository;

namespace S.M.SmartMedical.API.Write.Application.Handler;

/// <summary>
/// 提交开单申请处理器
/// </summary>
public class SubmitOrderApplicationHandler : IRequestHandler<SubmitOrderApplicationCommand, APIResult<OrderApplicationResultDto>>
{
    private readonly IRepository<OrderApplication> _orderApplicationRepository;
    private readonly IRepository<OrderApplicationItem> _orderApplicationItemRepository;
    private readonly IRepository<MedicalProject> _medicalProjectRepository;
    private readonly IRepository<User> _userRepository;
    private readonly IRepository<HospitalArea> _hospitalAreaRepository;
    private readonly MyDbContext _dbContext;
    private readonly IMapper _mapper;
    private readonly ILogger<SubmitOrderApplicationHandler> _logger;

    public SubmitOrderApplicationHandler(
        IRepository<OrderApplication> orderApplicationRepository,
        IRepository<OrderApplicationItem> orderApplicationItemRepository,
        IRepository<MedicalProject> medicalProjectRepository,
        IRepository<User> userRepository,
        IRepository<HospitalArea> hospitalAreaRepository,
        MyDbContext dbContext,
        IMapper mapper,
        ILogger<SubmitOrderApplicationHandler> logger)
    {
        _orderApplicationRepository = orderApplicationRepository;
        _orderApplicationItemRepository = orderApplicationItemRepository;
        _medicalProjectRepository = medicalProjectRepository;
        _userRepository = userRepository;
        _hospitalAreaRepository = hospitalAreaRepository;
        _dbContext = dbContext;
        _mapper = mapper;
        _logger = logger;
    }

    public async Task<APIResult<OrderApplicationResultDto>> Handle(SubmitOrderApplicationCommand request, CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation("开始处理开单申请，用户ID：{UserId}，院区ID：{HospitalAreaId}，项目数量：{ItemCount}", 
                request.UserId, request.HospitalAreaId, request.Items.Count);

            // 验证输入参数
            var validationResult = await ValidateRequestAsync(request);
            if (validationResult != null)
            {
                return validationResult;
            }

            // 获取医疗项目信息
            var medicalProjectIds = request.Items.Select(x => x.MedicalProjectId).ToList();
            var medicalProjects = await _medicalProjectRepository.GetQueryable()
                .Where(x => medicalProjectIds.Contains(x.Id) && x.IsEnabled && !x.IsDeleted)
                .ToListAsync(cancellationToken);

            if (medicalProjects.Count != medicalProjectIds.Count)
            {
                var missingIds = medicalProjectIds.Except(medicalProjects.Select(x => x.Id)).ToList();
                _logger.LogWarning("部分医疗项目不存在或已禁用，缺失的项目ID：{MissingIds}", string.Join(",", missingIds));
                
                return new APIResult<OrderApplicationResultDto>
                {
                    Code = APIEnum.Fail,
                    Message = "部分医疗项目不存在或已禁用",
                    Data = null!
                };
            }

            // 使用事务处理
            using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);
            try
            {
                // 创建开单申请
                var orderApplication = new OrderApplication
                {
                    ApplicationNumber = await GenerateApplicationNumberAsync(),
                    UserId = request.UserId,
                    HospitalAreaId = request.HospitalAreaId,
                    Status = OrderApplicationStatus.Pending,
                    Remarks = request.Remarks,
                    AppointmentDate = request.AppointmentDate,
                    AppointmentTimeSlot = request.AppointmentTimeSlot,
                    ContactPhone = request.ContactPhone,
                    CreateTime = DateTime.Now,
                    CreateUserName = request.UserId.ToString(),
                    IsDeleted = false
                };

                await _orderApplicationRepository.AddAsync(orderApplication);
                await _dbContext.SaveChangesAsync(cancellationToken);

                // 创建申请项目明细
                var orderApplicationItems = new List<OrderApplicationItem>();
                decimal totalAmount = 0;
                int totalQuantity = 0;

                foreach (var item in request.Items)
                {
                    var medicalProject = medicalProjects.First(x => x.Id == item.MedicalProjectId);
                    var subTotal = medicalProject.Price * item.Quantity;
                    
                    var orderApplicationItem = new OrderApplicationItem
                    {
                        OrderApplicationId = orderApplication.Id,
                        MedicalProjectId = item.MedicalProjectId,
                        ProjectName = medicalProject.Name,
                        ProjectPrice = medicalProject.Price,
                        ProjectDescription = medicalProject.Description,
                        Quantity = item.Quantity,
                        SubTotal = subTotal,
                        CreateTime = DateTime.Now,
                        CreateUserName = request.UserId.ToString(),
                        IsDeleted = false
                    };

                    orderApplicationItems.Add(orderApplicationItem);
                    totalAmount += subTotal;
                    totalQuantity += item.Quantity;
                }

                await _orderApplicationItemRepository.AddRangeAsync(orderApplicationItems);

                // 更新申请总金额和总数量
                orderApplication.TotalAmount = totalAmount;
                orderApplication.ProjectCount = totalQuantity;
                await _orderApplicationRepository.UpdateAsync(orderApplication);

                await _dbContext.SaveChangesAsync(cancellationToken);
                await transaction.CommitAsync(cancellationToken);

                _logger.LogInformation("开单申请提交成功，申请编号：{ApplicationNumber}，总金额：{TotalAmount}", 
                    orderApplication.ApplicationNumber, totalAmount);

                // 构建返回结果
                var result = new OrderApplicationResultDto
                {
                    Id = orderApplication.Id,
                    ApplicationNumber = orderApplication.ApplicationNumber,
                    Status = (int)orderApplication.Status,
                    ProjectCount = totalQuantity,
                    TotalAmount = totalAmount,
                    CreateTime = orderApplication.CreateTime,
                    Items = orderApplicationItems.Select(x => new OrderApplicationItemResultDto
                    {
                        Id = x.Id,
                        MedicalProjectId = x.MedicalProjectId,
                        ProjectName = x.ProjectName,
                        ProjectPrice = x.ProjectPrice,
                        ProjectDescription = x.ProjectDescription,
                        Quantity = x.Quantity,
                        SubTotal = x.SubTotal
                    }).ToList()
                };

                return new APIResult<OrderApplicationResultDto>
                {
                    Code = APIEnum.OK,
                    Message = "开单申请提交成功",
                    Data = result
                };
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync(cancellationToken);
                _logger.LogError(ex, "提交开单申请时发生异常，用户ID：{UserId}", request.UserId);
                
                // 获取完整的异常信息，包括内部异常
                var errorMessage = ex.InnerException != null 
                    ? $"{ex.Message} - 内部异常：{ex.InnerException.Message}"
                    : ex.Message;
                
                return new APIResult<OrderApplicationResultDto>
                {
                    Code = APIEnum.Fail,
                    Message = $"提交开单申请失败：{errorMessage}",
                    Data = null!
                };
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理开单申请时发生异常，用户ID：{UserId}", request.UserId);
            
            var errorMessage = ex.InnerException != null 
                ? $"{ex.Message} - 内部异常：{ex.InnerException.Message}"
                : ex.Message;
            
            return new APIResult<OrderApplicationResultDto>
            {
                Code = APIEnum.Fail,
                Message = $"处理开单申请失败：{errorMessage}",
                Data = null!
            };
        }
    }

    /// <summary>
    /// 验证请求参数
    /// </summary>
    private async Task<APIResult<OrderApplicationResultDto>?> ValidateRequestAsync(SubmitOrderApplicationCommand request)
    {
        // 验证用户是否存在
        var userExists = await _userRepository.GetQueryable()
            .AnyAsync(x => x.Id == request.UserId && !x.IsDeleted);
        if (!userExists)
        {
            _logger.LogWarning("用户不存在，用户ID：{UserId}", request.UserId);
            return new APIResult<OrderApplicationResultDto>
            {
                Code = APIEnum.Fail,
                Message = "用户不存在",
                Data = null!
            };
        }

        // 验证院区是否存在
        var hospitalAreaExists = await _hospitalAreaRepository.GetQueryable()
            .AnyAsync(x => x.Id == request.HospitalAreaId && !x.IsDeleted);
        if (!hospitalAreaExists)
        {
            _logger.LogWarning("院区不存在，院区ID：{HospitalAreaId}", request.HospitalAreaId);
            return new APIResult<OrderApplicationResultDto>
            {
                Code = APIEnum.Fail,
                Message = "院区不存在",
                Data = null!
            };
        }

        // 验证申请项目列表
        if (request.Items == null || !request.Items.Any())
        {
            _logger.LogWarning("申请项目列表为空，用户ID：{UserId}", request.UserId);
            return new APIResult<OrderApplicationResultDto>
            {
                Code = APIEnum.Fail,
                Message = "申请项目列表不能为空",
                Data = null!
            };
        }

        // 验证项目数量
        if (request.Items.Any(x => x.Quantity <= 0))
        {
            _logger.LogWarning("存在无效的项目数量，用户ID：{UserId}", request.UserId);
            return new APIResult<OrderApplicationResultDto>
            {
                Code = APIEnum.Fail,
                Message = "项目数量必须大于0",
                Data = null!
            };
        }

        return null;
    }

    /// <summary>
    /// 生成申请编号
    /// </summary>
    private async Task<string> GenerateApplicationNumberAsync()
    {
        var today = DateTime.Now.ToString("yyyyMMdd");
        var prefix = $"OA{today}";
        
        // 使用数据库查询获取最大序列号，避免并发冲突
        var maxSequence = await _orderApplicationRepository.GetQueryable()
            .Where(x => x.ApplicationNumber.StartsWith(prefix))
            .Select(x => x.ApplicationNumber)
            .ToListAsync();
        
        int maxNumber = 0;
        if (maxSequence.Any())
        {
            maxNumber = maxSequence
                .Select(s => int.TryParse(s.Substring(prefix.Length), out var num) ? num : 0)
                .DefaultIfEmpty(0)
                .Max();
        }
        
        var sequence = (maxNumber + 1).ToString("D4");
        return $"{prefix}{sequence}";
    }
}